﻿//
// <author>David Nohejl</author>
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using WPFTrees.Parser;
using System.Windows.Controls;
using System.Windows.Shapes;
using System.Windows;
using System.Windows.Media;
using WPFTrees.DataStructures;
using System.Diagnostics;

namespace WPFTrees.Tools
{
    /// <summary>
    /// Collection of helper methods.
    /// </summary>
    public static class TreeTools
    {
        internal static void ColorSubtree(NTreeNode<NewickNode> root, Brush brush)
        {
            foreach (NTreeNode<NewickNode> child in root.Children)
            {
                if (child != null)
                {
                    (child.Value().BranchToParentElement as Shape).Stroke = brush;
                    ColorSubtree(child, brush);
                }
            }
        }

        internal static void DetermineLabelVisibility(NewickNode node )
        {
            bool bShow = node.IsLeaf 
                ? DefaultSettings.Default.ShowLabels 
                : DefaultSettings.Default.ShowInternalLabels;
            Canvas nodeCanvas = (Canvas)node.VisualElement;
            Label label = nodeCanvas.Children[1] as Label;
            label.Visibility = bShow 
                ? System.Windows.Visibility.Visible 
                : System.Windows.Visibility.Hidden;
        }

        internal static void DetermineNodeVisibility(NTreeNode<NewickNode> root,
            NewickNode node)
        {
            Line line = node.BranchToParentElement as Line;
            if (root.Value().IsCollapsed)
            {
                line.Visibility = Visibility.Collapsed;
                node.VisualElement.Visibility = Visibility.Collapsed;
            }
            else
            {
                line.Visibility = Visibility.Visible;
                node.VisualElement.Visibility = Visibility.Visible;
            }
                        
        }

        // Gets ellipse from visual element of node.
        internal static Ellipse GetNodeEllipse(NTreeNode<NewickNode> node)
        {
            FrameworkElement visualElement = node.Value().VisualElement;
            Ellipse ellipse = (visualElement as Canvas).Children[0] as Ellipse;
            return ellipse;
        }
        internal static void SelectNode(NTreeNode<NewickNode> node)
        {
            Ellipse ellipse = GetNodeEllipse(node);
            ellipse.Fill = Brushes.Red;           
        }

        internal static void UnSelectNode(NTreeNode<NewickNode> node)
        {
            Ellipse ellipse = GetNodeEllipse(node);
            ellipse.Fill = Brushes.Transparent;
        }

        /// <summary>
        /// Rotates all children of <paramref name="node"/> by one position left.
        /// </summary>
        /// <param name="node">node whose childern will rotate</param>
        internal static void RotateLeft(NTreeNode<NewickNode> node)
        {
            Debug.Assert(node!=null);
            Debug.Assert(node.CountImmediateChildren > 1);

            NTreeNode<NewickNode> first;
            int count = node.CountImmediateChildren;
            first = node.Children[0];
            for (int i = 0; i < count-1; i++)
            {
                node.Children[i] = node.Children[i + 1];
            }
            node.Children[count-1] = first;
        }

        /// <summary>
        /// Rotates all children of <paramref name="node"/> by one position right.
        /// </summary>
        /// <param name="node">node whose children will rotate</param>
        internal static void RotateRight(NTreeNode<NewickNode> node)
        {
            Debug.Assert(node.CountImmediateChildren>1);
            NTreeNode<NewickNode> last;
            int count = node.CountImmediateChildren;
            last = node.Children[count-1];
            for (int i = count - 2; i > -1; i--)
            {
                node.Children[i + 1] = node.Children[i];
            }
            node.Children[0] = last;

        }

        /// <summary>
        /// Recursively sorts subtrees of <paramref name="root"/> by number 
        /// of leaves in each subtree, 
        /// subtrees with largest number of leaves are most on the left.
        /// </summary>
        /// <param name="root">node which will be ladderized</param>
        internal static void LadderizeLeft(NTreeNode<NewickNode> root)
        {
            Array.Sort<NTreeNode<NewickNode>>(root.Children, 0, 
                root.CountImmediateChildren, new CladeSizeComparer(true));

            foreach (NTreeNode<NewickNode> child in root.Children)
            {
                if (child != null)
                    LadderizeLeft(child);
            }
        }

        /// <summary>
        /// Recursively sorts subtrees of <paramref name="root"/> by number 
        /// of leaves in each subtree, 
        /// subtrees with largest number of leaves are most on the right.
        /// </summary>
        /// <param name="root">node which will be ladderized</param>
        internal static void LadderizeRight(NTreeNode<NewickNode> root)
        {
            Array.Sort<NTreeNode<NewickNode>>(root.Children, 0, 
                root.CountImmediateChildren, new CladeSizeComparer(false));

            foreach (NTreeNode<NewickNode> child in root.Children)
            {
                if (child != null)
                    LadderizeRight(child);
            }
        }

        /// <summary>
        /// Collapses or expands subtree by recursively changing the IsCollapsed
        /// property of nodes.
        /// </summary>
        /// <param name="root">Root of subtree to expand/collapse</param>
        /// <param name="value">true for collapsing, false for expanding</param>
        internal static void CollapseOrExpandSubtree(NTreeNode<NewickNode> root,
            bool value)
        {
            GroupInfo info = root.Value().GroupInfo;
            if (info != null)
            {
                if(value)
                {
                    info.Shape.Visibility = Visibility.Collapsed;
                }
                else
                { 
                    info.Shape.Visibility = Visibility.Visible;
                }
            }
        

            foreach (NTreeNode<NewickNode> child in root.Children)
            {
                if (child != null)
                {
                    child.Value().IsCollapsed = value;
                    CollapseOrExpandSubtree(child, value);
                }
            }
        }
    }
}
